using System;
using MathLib;

namespace UraniaLib
{
	/// <summary>
	/// Summary description for UraniaMoon.
	/// </summary>
	public class UraniaMoon
	{
		private UraniaPlanetData UraniaPlanetData = new UraniaPlanetData();

		public UraniaMoon()
		{
		}

		public static void CalcMoonPos(DateTime dDate, DateTime dEpoch, double fMEpochLong, double fMPeriLong, double fMAscNode, double fMIncl, double fMEcc, double fSEpochEclLong, double fSPeriEclLong, double fSEcc, ref double fMRA, ref double fMDecl)
		{
			double fN, fSM, fSE, fSLambda;
			double fL, fMM, fMN, fME, fAE, fMEC, fA3, fA4, fMV, fMM1, fL1, fL2, fN1, fX, fY;
			double fT, fMLambda, fMBeta, fJD1, fJD2, fDays;

			fJD1 = UraniaTime.GetJulianDay(dDate, 0);
			fJD2 = UraniaTime.GetJulianDay(dEpoch, 0);
			fDays = (fJD1 - fJD2);
			fDays += 1;

			fN = (360.0/365.242191) * fDays;
			fN = Trig.PutIn360Deg(fN);
			fSM = fN + fSEpochEclLong - fSPeriEclLong;
			fSM = Trig.PutIn360Deg(fSM);

			fSE = (360.0 / Math.PI) * fSEcc * Math.Sin(Trig.DegToRad(fSM));
			fSLambda = fN + fSE + fSEpochEclLong;

			fL = (13.176396 * fDays) + fMEpochLong;
			fL = Trig.PutIn360Deg(fL);
			
			fMM = fL - (0.111404 * fDays) - fMPeriLong;
			fMM = Trig.PutIn360Deg(fMM);

			fMN = fMAscNode - (0.0529539 * fDays);
			fMN = Trig.PutIn360Deg(fMN);

			fME = 1.2739 * Trig.Sin((2.0 * (fL - fSLambda)) - fMM);
			fAE = 0.1858 * Trig.Sin(fSM);
			fA3 = 0.37 * Trig.Sin(fSM);

			fMM1 = fMM + fME - fAE + fA3;
			
			fMEC = 6.2886 * Trig.Sin(fMM1);
			fA4 = 0.214 * Trig.Sin(2.0 * fMM1);
			fL1 = fL + fME + fMEC - fAE + fA4;

			fMV = 0.6583 * Trig.Sin(2.0 * (fL1 - fSLambda));
			fL2 = fL1 + fMV;

			fN1 = fMN - (0.16 * Trig.Sin(fSM));
			fY = Trig.Sin(fL2 - fN1) * Trig.Cos(fMIncl);
			fX = Trig.Cos(fL2 - fN1);

			fT = Trig.Atan(fY / fX);

			fT = Trig.TanQuadrant(fX, fY, fT);
			
			fMLambda = fT + fN1;
			fMBeta = Trig.Asin(Trig.Sin(fL2 - fN1) * Trig.Sin(fMIncl));
			UraniaCoord.ConvEclToEqu(23.441884,fMLambda, fMBeta, ref fMRA, ref fMDecl);
		}

		public static void CalcMoonPhase(DateTime dDate, DateTime dEpoch, double fMEpochLong, double fMPeriLong, double fMAscNode, double fMIncl, double fMEcc, double fSEpochEclLong, double fSPeriEclLong, double fSEcc, ref double fMPhase)
		{
			double fN, fSM, fSE, fSLambda;
			double fL, fMM, fMN, fME, fAE, fMEC, fA3, fA4, fMV, fMM1, fL1, fL2;
			double fJD1, fJD2, fDays, fMD;

			fJD1 = UraniaTime.GetJulianDay(dDate, 0);
			fJD2 = UraniaTime.GetJulianDay(dEpoch, 0);
			fDays = (fJD1 - fJD2);
			fDays += 1;

			fN = (360.0/365.242191) * fDays;
			fN = Trig.PutIn360Deg(fN);
			fSM = fN + fSEpochEclLong - fSPeriEclLong;
			fSM = Trig.PutIn360Deg(fSM);

			fSE = (360.0 / Math.PI) * fSEcc * Math.Sin(Trig.DegToRad(fSM));
			fSLambda = fN + fSE + fSEpochEclLong;

			fL = (13.176396 * fDays) + fMEpochLong;
			fL = Trig.PutIn360Deg(fL);
			
			fMM = fL - (0.111404 * fDays) - fMPeriLong;
			fMM = Trig.PutIn360Deg(fMM);

			fMN = fMAscNode - (0.0529539 * fDays);
			fMN = Trig.PutIn360Deg(fMN);

			fME = 1.2739 * Trig.Sin((2.0 * (fL - fSLambda)) - fMM);
			fAE = 0.1858 * Trig.Sin(fSM);
			fA3 = 0.37 * Trig.Sin(fSM);

			fMM1 = fMM + fME - fAE + fA3;
			
			fMEC = 6.2886 * Trig.Sin(fMM1);
			fA4 = 0.214 * Trig.Sin(2.0 * fMM1);
			fL1 = fL + fME + fMEC - fAE + fA4;

			fMV = 0.6583 * Trig.Sin(2.0 * (fL1 - fSLambda));
			fL2 = fL1 + fMV;

			fMD = fL2 - fSLambda;
			fMPhase = 0.5 * (1.0 - Trig.Cos(fMD));


		}

		public static void CalcMoonDistance(DateTime dDate, DateTime dEpoch, double fMEpochLong, double fMPeriLong, double fMAscNode, double fMIncl, double fMEcc, double fSEpochEclLong, double fSPeriEclLong, double fSEcc, double fMSMA, ref double fMDistance)
		{
			double fN, fSM, fSE, fSLambda;
			double fL, fMM, fMN, fME, fAE, fMEC, fA3, fMM1;
			double fJD1, fJD2, fDays;

			fJD1 = UraniaTime.GetJulianDay(dDate, 0);
			fJD2 = UraniaTime.GetJulianDay(dEpoch, 0);
			fDays = (fJD1 - fJD2);
			fDays += 1;

			fN = (360.0/365.242191) * fDays;
			fN = Trig.PutIn360Deg(fN);
			fSM = fN + fSEpochEclLong - fSPeriEclLong;
			fSM = Trig.PutIn360Deg(fSM);

			fSE = (360.0 / Math.PI) * fSEcc * Math.Sin(Trig.DegToRad(fSM));
			fSLambda = fN + fSE + fSEpochEclLong;

			fL = (13.176396 * fDays) + fMEpochLong;
			fL = Trig.PutIn360Deg(fL);
			
			fMM = fL - (0.111404 * fDays) - fMPeriLong;
			fMM = Trig.PutIn360Deg(fMM);

			fMN = fMAscNode - (0.0529539 * fDays);
			fMN = Trig.PutIn360Deg(fMN);

			fME = 1.2739 * Trig.Sin((2.0 * (fL - fSLambda)) - fMM);
			fAE = 0.1858 * Trig.Sin(fSM);
			fA3 = 0.37 * Trig.Sin(fSM);

			fMM1 = fMM + fME - fAE + fA3;
			
			fMEC = 6.2886 * Trig.Sin(fMM1);

			fMDistance = fMSMA * ((1.0 - (fMEcc * fMEcc))/(1.0 + (fMEcc * Trig.Cos(fMM1 + fMEC))));
		}

		public static void CalcMoonDiam(DateTime dDate, DateTime dEpoch, double fMEpochLong, double fMPeriLong, double fMAscNode, double fMIncl, double fMEcc, double fSEpochEclLong, double fSPeriEclLong, double fSEcc, double fMSMA, double fVAngDiam, ref double fMAngDiam)
		{
			double fRho;

			fRho = 0;
			CalcMoonDistance(dDate, dEpoch, fMEpochLong, fMPeriLong, fMAscNode, fMIncl, fMEcc, fSEpochEclLong, fSPeriEclLong, fSEcc, fMSMA, ref fRho);

			fMAngDiam = fVAngDiam / (fRho / fMSMA);
		}

		public static void CalcMoonParallax(DateTime dDate, DateTime dEpoch, double fMEpochLong, double fMPeriLong, double fMAscNode, double fMIncl, double fMEcc, double fSEpochEclLong, double fSPeriEclLong, double fSEcc, double fMSMA, double fVParallax, ref double fMParallax)
		{
			double fRho;

			fRho = 0;
			CalcMoonDistance(dDate, dEpoch, fMEpochLong, fMPeriLong, fMAscNode, fMIncl, fMEcc, fSEpochEclLong, fSPeriEclLong, fSEcc, fMSMA, ref fRho);

			fMParallax = fVParallax / (fRho / fMSMA);
		}

		public static double CalcMoonBrightLimb(double fSunRA, double fSunDecl, double fMRA, double fMDecl)
		{
			double fX, fY, fT, fDeltaRA;

			fSunRA = fSunRA * 15;
			fMRA = fMRA * 15;
			fDeltaRA = fSunRA - fMRA;

			fY = Trig.Cos(fSunDecl) * Trig.Sin(fDeltaRA);
			fX = (Trig.Cos(fMDecl) * Trig.Sin(fSunDecl)) - (Trig.Sin(fMDecl) * Trig.Cos(fSunDecl) * Trig.Cos(fDeltaRA));
			fT = Trig.Atan(fY / fX);
			return Trig.TanQuadrant(fX, fY, fT);
		}
		public static double CalcMoonAge(DateTime dDate, int iZone)
		{
			double fJD, fIP, fAge;

			fJD = UraniaTime.GetJulianDay(dDate, iZone);
			fIP = Normalize((fJD - 2451550.1) / 29.530588853);
			fAge = fIP*29.53;;
            return fAge;
		}

		public static string GetMoonStage(double fAge)
		{
			string sStage;

			if (fAge < 1.84566)
			{
				sStage = "New";
			}
			else if (fAge < 5.53699)
			{
				sStage = "Waxing Crescent";
			}
			else if (fAge < 9.22831)
			{
				sStage = "First Quarter";
			}
			else if (fAge < 12.91963)
			{
				sStage = "Waxing Gibbous";
			}
			else if (fAge < 16.61096)
			{
				sStage = "Full";
			}
			else if (fAge < 20.30228)
			{
				sStage = "Waning Gibbous";
			}
			else if (fAge < 23.9931)
			{
				sStage = "Last Quater";
			}
			else if (fAge < 27.68493)
			{
				sStage = "Waning Crescent";
			}
			else
			{
				sStage = "New";
			}

			return sStage;
		}

		private static double Normalize(double fN)
		{
			fN = fN - Math.Floor(fN);
			if (fN < 0)
			{
				fN = fN + 1;
			}
			return fN;
		}
	}
}
